/*
 * Copyright (c) 2000-2017 wanglei. All rights reserved.
 * TeamDev PROPRIETARY and CONFIDENTIAL.
 * Use is subject to license terms.
 */

package com.xhb.ui;

import com.teamdev.jxbrowser.browser.Browser;
import com.xhb.ui.resources.Resources;
import com.teamdev.jxbrowser.frame.EditorCommand;
import com.teamdev.jxbrowser.navigation.event.LoadFinished;
import com.teamdev.jxbrowser.navigation.event.LoadStarted;
import com.teamdev.jxbrowser.view.swing.BrowserView;

import javax.swing.*;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import java.awt.*;
import java.awt.event.*;
import java.io.File;

/**
 * @author wanglei.
 */
public class ToolBar extends JPanel {
    private static final String RUN_JAVASCRIPT = "Run JavaScript...";
    private static final String CLOSE_JAVASCRIPT = "Close JavaScript Console";
    private static final String DEFAULT_URL = "about:blank";

    private JButton backwardButton;
    private JButton forwardButton;
    private JButton refreshButton;
    private JButton stopButton;
    private JMenuItem consoleMenuItem;

    private final JTextField addressBar;
    private final BrowserView browserView;

    public ToolBar(BrowserView browserView) {
        this.browserView = browserView;

        addressBar = createAddressBar();
        setLayout(new GridBagLayout());
        add(createActionsPane(), new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST,
                GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
        add(addressBar, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0,
                GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(4, 0, 4, 5), 0, 0));
        add(createMenuButton(), new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0,
                GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 5), 0, 0));
    }

    public void setUrl(String url){
        addressBar.setText(url);
    }

    public void didJSConsoleClose() {
        consoleMenuItem.setText(RUN_JAVASCRIPT);
    }

    private JPanel createActionsPane() {
        backwardButton = createBackwardButton(browserView.getBrowser());
        forwardButton = createForwardButton(browserView.getBrowser());
        refreshButton = createRefreshButton(browserView.getBrowser());
        stopButton = createStopButton(browserView.getBrowser());

        JPanel actionsPanel = new JPanel();
        actionsPanel.add(backwardButton);
        actionsPanel.add(forwardButton);
        actionsPanel.add(refreshButton);
        actionsPanel.add(stopButton);
        return actionsPanel;
    }

    private JTextField createAddressBar() {
        final JTextField result = new JTextField(DEFAULT_URL);
        result.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl(result.getText());
            }
        });
        browserView.getBrowser().navigation().on(LoadStarted.class, event -> {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    refreshButton.setEnabled(false);
                    stopButton.setEnabled(true);
                }
            });
        });
        browserView.getBrowser().navigation().on(LoadFinished.class, event -> {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    forwardButton.setEnabled(event.navigation().canGoForward());
                    backwardButton.setEnabled(event.navigation().canGoBack());
                    refreshButton.setEnabled(true);
                    stopButton.setEnabled(false);
                    result.setText(event.navigation().browser().url());
                }
            });
        });
        return result;
    }

    private static JButton createBackwardButton(final Browser browser) {
        return createButton("Back", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                browser.navigation().goBack();
            }
        });
    }

    private static JButton createForwardButton(final Browser browser) {
        return createButton("Forward", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                browser.navigation().goForward();
            }
        });
    }

    private static JButton createRefreshButton(final Browser browser) {
        return createButton("Refresh", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                browser.navigation().reload();
            }
        });
    }

    private static JButton createStopButton(final Browser browser) {
        return createButton("Stop", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                browser.navigation().stop();
            }
        });
    }

    private static JButton createButton(String caption, Action action) {
        ActionButton button = new ActionButton(caption, action);
        String imageName = caption.toLowerCase();
        button.setIcon(Resources.getIcon(imageName + ".png"));
        button.setRolloverIcon(Resources.getIcon(imageName + "-selected.png"));
        return button;
    }

    private JComponent createMenuButton() {
        final JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.add(createConsoleMenuItem());
        popupMenu.add(createGetHTMLMenuItem());
        popupMenu.add(createPopupsMenuItem());
        popupMenu.add(createUploadFileMenuItem());
        popupMenu.add(createDownloadFileMenuItem());
        popupMenu.add(createJavaScriptDialogsMenuItem());
        popupMenu.add(createPDFViewerMenuItem());
        popupMenu.add(createGoogleMapsMenuItem());
        popupMenu.add(createHTML5VideoMenuItem());
        popupMenu.add(createZoomInMenuItem());
        popupMenu.add(createZoomOutMenuItem());
        popupMenu.add(createActualSizeMenuItem());
        popupMenu.add(createSaveWebPageMenuItem());
        popupMenu.add(createClearCacheMenuItem());
        popupMenu.add(createPreferencesSubMenu());
        popupMenu.add(createExecuteCommandSubMenu());
        popupMenu.add(createPrintMenuItem());
        popupMenu.addSeparator();
        popupMenu.add(createMoreMenuItem());
        popupMenu.addSeparator();
        popupMenu.add(createAboutMenuItem());

        final ActionButton button = new ActionButton("Preferences", null);
        button.setIcon(Resources.getIcon("gear.png"));
        button.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
                    popupMenu.show(e.getComponent(), 0, button.getHeight());
                } else {
                    popupMenu.setVisible(false);
                }
            }
        });
        return button;
    }

    private Component createPrintMenuItem() {
        JMenuItem menuItem = new JMenuItem("打印");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().mainFrame().get().print();
            }
        });
        return menuItem;
    }

    private Component createPreferencesSubMenu() {
        JMenu menu = new JMenu("首选项");
        menu.add(createCheckBoxMenuItem("启用JS", browserView.getBrowser().settings().isJavaScriptEnabled(), new CheckBoxMenuItemCallback() {
            public void call(boolean selected) {
                if(selected){
                    browserView.getBrowser().settings().enableJavaScript();
                }
                else{
                    browserView.getBrowser().settings().disableJavaScript();
                }
                browserView.getBrowser().navigation().reloadIgnoringCache();
            }
        }));
        menu.add(createCheckBoxMenuItem("加载图片", browserView.getBrowser().settings().isImagesEnabled(), new CheckBoxMenuItemCallback() {
            public void call(boolean selected) {
                if(selected){
                    browserView.getBrowser().settings().enableImages();
                }
                else{
                    browserView.getBrowser().settings().disableImages();
                }
                browserView.getBrowser().navigation().reloadIgnoringCache();
            }
        }));
        menu.add(createCheckBoxMenuItem("插件支持", browserView.getBrowser().settings().isPluginsEnabled(), new CheckBoxMenuItemCallback() {
            public void call(boolean selected) {
                if(selected){
                    browserView.getBrowser().settings().enablePlugins();
                }
                else{
                    browserView.getBrowser().settings().disablePlugins();
                }
                browserView.getBrowser().navigation().reloadIgnoringCache();
            }
        }));
        return menu;
    }

    private static JCheckBoxMenuItem createCheckBoxMenuItem(String title, boolean selected, final CheckBoxMenuItemCallback action) {
        final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(title, selected);
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                action.call(menuItem.isSelected());
            }
        });
        return menuItem;
    }

    private Component createClearCacheMenuItem() {
        JMenuItem menuItem = new JMenuItem("清理缓存");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().profile().httpCache().clear().join();
                browserView.getBrowser().profile().cookieStore().deleteAll();
                browserView.getBrowser().profile().cookieStore().persist();
            }
        });
        return menuItem;
    }

    private Component createExecuteCommandSubMenu() {
        final JMenu menu = new JMenu("执行命令");
        menu.addMenuListener(new MenuListener() {
            public void menuSelected(MenuEvent e) {
                Component[] menuItems = menu.getMenuComponents();
                for (Component menuItem : menuItems) {
                    menuItem.setEnabled(browserView.getBrowser().mainFrame().get().isCommandEnabled(((CommandMenuItem) menuItem).getCommand().name()));
                }
            }

            public void menuDeselected(MenuEvent e) {

            }

            public void menuCanceled(MenuEvent e) {

            }
        });

        menu.add(createExecuteCommandSubMenuItem("Cut", EditorCommand.cut()));
        menu.add(createExecuteCommandSubMenuItem("Copy", EditorCommand.copy()));
        menu.add(createExecuteCommandSubMenuItem("Paste", EditorCommand.paste()));
        menu.add(createExecuteCommandSubMenuItem("Select All", EditorCommand.selectAll()));
        menu.add(createExecuteCommandSubMenuItem("Unselect", EditorCommand.unselect()));
        menu.add(createExecuteCommandSubMenuItem("Undo", EditorCommand.undo()));
        menu.add(createExecuteCommandSubMenuItem("Redo", EditorCommand.redo()));/*
        menu.add(createExecuteCommandSubMenuItem("Insert Text...", "Insert Text", EditorCommand.ins));
        menu.add(createExecuteCommandSubMenuItem("Find Text...", "Find Text", EditorCommand.find));*/
        return menu;
    }

    private Component createExecuteCommandSubMenuItem(final String commandName, final EditorCommand command) {
        final CommandMenuItem menuItem = new CommandMenuItem(commandName, command);
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().mainFrame().get().execute(command);
            }
        });
        return menuItem;
    }

    private Component createExecuteCommandSubMenuItem(final String commandName, final String dialogTitle, final EditorCommand command) {
        final CommandMenuItem menuItem = new CommandMenuItem(commandName, command);
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String value = JOptionPane.showInputDialog(browserView, "Command value:", dialogTitle, JOptionPane.PLAIN_MESSAGE);
                browserView.getBrowser().mainFrame().get().execute(command);
            }
        });
        return menuItem;
    }

    private Component createMoreMenuItem() {
        JMenuItem menuItem = new JMenuItem("更多特性");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("http://www.cptcsoft.com");
            }
        });
        return menuItem;
    }

    private Component createSaveWebPageMenuItem() {
        JMenuItem menuItem = new JMenuItem("保存页面");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setSelectedFile(new File("my-web-page.html"));
                int result = fileChooser.showSaveDialog(browserView);
                if (result == JFileChooser.APPROVE_OPTION) {
                    File selectedFile = fileChooser.getSelectedFile();
                    String dirPath = new File(selectedFile.getParent(), "resources").getAbsolutePath();
                    //browserView.getBrowser().saveWebPage(selectedFile.getAbsolutePath(), dirPath, SavePageType.COMPLETE_HTML);
                }
            }
        });
        return menuItem;
    }

    private Component createActualSizeMenuItem() {
        JMenuItem menuItem = new JMenuItem("还原");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().profile();
            }
        });
        return menuItem;
    }

    private Component createZoomOutMenuItem() {
        JMenuItem menuItem = new JMenuItem("缩小");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().zoom().out();
            }
        });
        return menuItem;
    }

    private Component createZoomInMenuItem() {
        JMenuItem menuItem = new JMenuItem("放大");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().zoom().in();
            }
        });
        return menuItem;
    }

    private Component createHTML5VideoMenuItem() {
        JMenuItem menuItem = new JMenuItem("直播测试");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("https://live.bilibili.com/");
            }
        });
        return menuItem;
    }

    private Component createGoogleMapsMenuItem() {
        JMenuItem menuItem = new JMenuItem("Echarts演示");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("https://echarts.apache.org/examples/zh/index.html");
            }
        });
        return menuItem;
    }

    private Component createJavaScriptDialogsMenuItem() {
        JMenuItem menuItem = new JMenuItem("VUE支持");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("https://element.eleme.cn/#/zh-CN/component/switch");
            }
        });
        return menuItem;
    }

    private Component createDownloadFileMenuItem() {
        JMenuItem menuItem = new JMenuItem("下载文件测试");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("http://www.51xiazai.cn/soft/85579.htm");
            }
        });
        return menuItem;
    }

    private Component createGetHTMLMenuItem() {
        JMenuItem menuItem = new JMenuItem("获取HTML");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String html = browserView.getBrowser().mainFrame().get().html();
                Window window = SwingUtilities.getWindowAncestor(browserView);
                JDialog dialog = new JDialog(window);
                dialog.setModal(true);
                dialog.setContentPane(new JScrollPane(new JTextArea(html)));
                dialog.setSize(700, 500);
                dialog.setLocationRelativeTo(null);
                dialog.setVisible(true);

            }
        });
        return menuItem;
    }

    private JMenuItem createConsoleMenuItem() {
        consoleMenuItem = new JMenuItem(RUN_JAVASCRIPT);
        consoleMenuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (RUN_JAVASCRIPT.equals(consoleMenuItem.getText())) {
                    consoleMenuItem.setText(CLOSE_JAVASCRIPT);
                    firePropertyChange("JSConsoleDisplayed", false, true);
                } else {
                    consoleMenuItem.setText(RUN_JAVASCRIPT);
                    firePropertyChange("JSConsoleClosed", false, true);
                }
            }
        });
        return consoleMenuItem;
    }

    private JMenuItem createUploadFileMenuItem() {
        JMenuItem menuItem = new JMenuItem("Upload File");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("http://www.cs.tut.fi/~jkorpela/forms/file.html#example");
            }
        });
        return menuItem;
    }

    private JMenuItem createPopupsMenuItem() {
        JMenuItem menuItem = new JMenuItem("Popup Windows");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("http://www.popuptest.com");
            }
        });
        return menuItem;
    }

    private JMenuItem createPDFViewerMenuItem() {
        JMenuItem menuItem = new JMenuItem("PDF预览");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                browserView.getBrowser().navigation().loadUrl("http://www.orimi.com/pdf-test.pdf");
            }
        });
        return menuItem;
    }



    private JMenuItem createAboutMenuItem() {
        JMenuItem menuItem = new JMenuItem("关于我们");
        menuItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Frame parentFrame = (Frame) SwingUtilities.getWindowAncestor(ToolBar.this);
                AboutDialog aboutDialog = new AboutDialog(parentFrame);
                aboutDialog.setVisible(true);
            }
        });
        return menuItem;
    }

    private boolean isFocusRequired() {
        String url = addressBar.getText();
        return url.isEmpty() || url.equals(DEFAULT_URL);
    }

    @Override
    public void addNotify() {
        super.addNotify();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (isFocusRequired()) {
                    addressBar.requestFocus();
                    addressBar.selectAll();
                }
            }
        });
    }

    private static class ActionButton extends JButton {
        private ActionButton(String hint, Action action) {
            super(action);
            setContentAreaFilled(false);
            setBorder(BorderFactory.createEmptyBorder());
            setBorderPainted(false);
            setRolloverEnabled(true);
            setToolTipText(hint);
            setText(null);
            setFocusable(false);
            setDefaultCapable(false);
        }
    }

    private interface CheckBoxMenuItemCallback {
        void call(boolean selected);
    }
}
